package views;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.*;

import controllers.Driver;
import controllers.EventHandler;
import controllers.MyTableModel;
import controllers.Event;
import controllers.Vehicle;
import db.DriverDAO;
import db.EventDAO;
import db.VehicleDAO;
import java.awt.print.PrinterException;
import java.text.MessageFormat;
import java.util.EventListener;
import java.util.GregorianCalendar;

public class mainFrame extends JFrame {

    private final static String TITLE = "CSSA Van Scheduling";
    private static final int WIDTH = 1000;
    private static final int HEIGHT = 650;
    private static final int XBOUND = 50;
    private static final int YBOUND = 50;
    private static JMenuBar menuBar;
    private static JLabel dateLabel;
    static List<controllers.Event> eventsList;
    public static myTable table;
    private static MyTableModel model;
    private static Object[][] events;
    private static Object[] columnNames = {"Date", "Drive Time", "Depart JCU", "Driver", "Transportation", "Service Time", "Site", "# attending", "Notes"};
    private static JScrollPane scrollpane;
    private static SimpleDateFormat sdf = new SimpleDateFormat("EEE, MMM dd");
    private static SimpleDateFormat sdf2 = new SimpleDateFormat("hh:mm a");
    private static SimpleDateFormat sdf3 = new SimpleDateFormat("EEEE, MMMM dd, yyyy");
    private static Calendar baseCal = Calendar.getInstance();
    private static GregorianCalendar cal, mutableCal;
    static int selectedIndex;
    private static Driver[] driverArray;
    private static JButton back, forward, goToToday, print;
    public static Container content;
    private String dayOrWeek = "";
    private static JRadioButton weekly, daily, allDriversBtn, possDriversBtn;
    private static int radioSet;
    private static boolean weeklybool = false;
    private static boolean allDriversBool = false;
    public static Event editingEvent;

    public mainFrame() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle(TITLE);
        this.setBounds(XBOUND, YBOUND, WIDTH, HEIGHT);
        this.setResizable(false);
        content = this.getContentPane();
        content.setLayout(null);
        //content.setBackground(new Color(00,33,66));

        baseCal = Calendar.getInstance();

        cal = new GregorianCalendar(baseCal.get(Calendar.YEAR),
                baseCal.get(Calendar.MONTH), baseCal.get(Calendar.DAY_OF_MONTH));
        mutableCal = new GregorianCalendar();
        mutableCal.setTimeInMillis(cal.getTimeInMillis());

        scrollpane = new JScrollPane();
        content.add(scrollpane);
        updateTable();

        List<Driver> driverList = DriverDAO.getDrivers();
        driverArray = new Driver[driverList.size()];

        for (int i = 0; i < driverList.size(); i++) {
            driverArray[i] = driverList.get(i);
        }

        dateLabel = new JLabel(dayOrWeek + sdf3.format(cal.getTimeInMillis()));
        dateLabel.setBounds(50, 15, 700, 30);
        dateLabel.setFont(new java.awt.Font("Tahoma", 1, 24));
        content.add(dateLabel);

        back = new JButton(" << ");
        back.setBounds(50, 460, 100, 30);
        back.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (weeklybool) {
                    cal.setTimeInMillis(cal.getTimeInMillis() - (60 * 60 * 1000 * 24 * 7));
                } else {
                    cal.setTimeInMillis(cal.getTimeInMillis() - (60 * 60 * 1000 * 24));
                }
                dateLabel.setText(dayOrWeek + sdf3.format(cal.getTimeInMillis()));

                if (!forward.isEnabled()) {
                    forward.setEnabled(true);
                }

                updateTable();
            }
        });
        content.add(back);

        forward = new JButton(" >> ");
        forward.setBounds(160, 460, 100, 30);
        forward.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (weeklybool) {
                    cal.setTimeInMillis(cal.getTimeInMillis() + (60 * 60 * 1000 * 24 * 7));
                    if (cal.getTimeInMillis() > baseCal.getTimeInMillis() + 60 * 60 * 1000 * 24 * 14) {
                        forward.setEnabled(false);
                    }
                } else {
                    cal.setTimeInMillis(cal.getTimeInMillis() + (60 * 60 * 1000 * 24));
                    if (cal.getTimeInMillis() > baseCal.getTimeInMillis() + 60 * 60 * 1000 * 24 * 14) {
                        forward.setEnabled(false);
                    }
                }
                updateTable();

                dateLabel.setText(dayOrWeek + sdf3.format(cal.getTimeInMillis()));
            }
        });
        content.add(forward);

        goToToday = new JButton("Go to Today");
        goToToday.setBounds(270, 460, 100, 30);
        goToToday.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                cal = new GregorianCalendar(baseCal.get(Calendar.YEAR),
                        baseCal.get(Calendar.MONTH), baseCal.get(Calendar.DAY_OF_MONTH));
                dateLabel.setText(dayOrWeek + sdf3.format(cal.getTimeInMillis()));
                updateTable();
            }
        });
        content.add(goToToday);

        print = new JButton("Print");
        print.setBounds(380, 460, 100, 30);
        print.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    MessageFormat headerFormat = new MessageFormat(dayOrWeek + sdf3.format(cal.getTimeInMillis()));
                    MessageFormat footerFormat = new MessageFormat("- {0} -");
                    table.print(JTable.PrintMode.FIT_WIDTH, headerFormat, footerFormat);
                } catch (PrinterException pe) {
                    System.err.println("Error printing: " + pe.getMessage());
                }
            }
        });
        content.add(print);

        weekly = new JRadioButton("Weekly");
        weekly.setBounds(50, 500, 100, 20);
        weekly.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                dayOrWeek = "Week Of ";
                cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
                dateLabel.setText(dayOrWeek + sdf3.format(cal.getTimeInMillis()));
                weeklybool = true;
                radioSet = 0;
                updateTable();
            }
        });

        daily = new JRadioButton("Daily");
        daily.setBounds(50, 525, 100, 20);
        daily.setSelected(true);
        daily.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                dayOrWeek = "";
                dateLabel.setText(dayOrWeek + sdf3.format(cal.getTimeInMillis()));
                weeklybool = false;
                radioSet = 1;
                updateTable();
            }
        });

        ButtonGroup bg = new ButtonGroup();
        bg.add(weekly);
        bg.add(daily);

        content.add(weekly);
        content.add(daily);

        possDriversBtn = new JRadioButton("Show Only Possible Drivers");
        possDriversBtn.setBounds(150, 500, 200, 20);
        possDriversBtn.setSelected(true);
        possDriversBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                allDriversBool = false;
            }
        });

        allDriversBtn = new JRadioButton("Show All Drivers");
        allDriversBtn.setBounds(150, 525, 200, 20);
        allDriversBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                allDriversBool = true;
            }
        });

        ButtonGroup bg2 = new ButtonGroup();
        bg2.add(possDriversBtn);
        bg2.add(allDriversBtn);

        content.add(possDriversBtn);
        content.add(allDriversBtn);

        menuBar = new JMenuBar();

        JMenu file = new JMenu("File");

        JMenuItem GenerateEvents = new JMenuItem("Generate Events");
        GenerateEvents.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                if (cal.get(Calendar.DAY_OF_MONTH) < baseCal.get(Calendar.DAY_OF_MONTH)
                        && cal.get(Calendar.DAY_OF_YEAR) < baseCal.get(Calendar.DAY_OF_YEAR)
                        && cal.get(Calendar.MONTH) < baseCal.get(Calendar.MONTH)) {
                    Object[] options = {"No, Don't Regenerate", "Yes, Regenerate"};
                    int choice = JOptionPane.showOptionDialog(getComponent(0), "Are you sure you want to generate events for this week in the past?", "Regenerate?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]);
                    switch (choice) {
                        case 0:
                            break;
                        case 1:
                            new ProgressBar(getX() + WIDTH / 2, getY() + HEIGHT / 2, cal);
                            if (weeklybool) {
                                mutableCal.setTimeInMillis(cal.getTimeInMillis()
                                        + (1000 * 60 * 60 * 24));
                                for (int i = 0; i < 6; i++) {
                                    new ProgressBar(getX() + WIDTH / 2, getY() + HEIGHT / 2, mutableCal);
                                    mutableCal.setTimeInMillis(mutableCal.getTimeInMillis()
                                            + (1000 * 60 * 60 * 24));
                                }
                            }

                            break;

                        default:
                            break;
                    }
                } else {
                    new ProgressBar(getX() + WIDTH / 2, getY() + HEIGHT / 2, cal);
                    if (weeklybool) {
                        mutableCal.setTimeInMillis(cal.getTimeInMillis()
                                + (1000 * 60 * 60 * 24));
                        for (int i = 0; i < 6; i++) {
                            new ProgressBar(getX() + WIDTH / 2, getY() + HEIGHT / 2, mutableCal);
                            mutableCal.setTimeInMillis(mutableCal.getTimeInMillis()
                                    + (1000 * 60 * 60 * 24));
                        }
                    }
                }
                updateTable();
            }
        });
        file.add(GenerateEvents);
        file.add(new JSeparator());

        JMenuItem Exit = new JMenuItem("Exit");
        Exit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        file.add(Exit);

        JMenu drivers = new JMenu("Drivers");
        JMenuItem addDriver = new JMenuItem("Add Driver");
        drivers.add(addDriver);
        addDriver.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                new AddDriverFrame(getXBound(), getYBound());
            }
        });
        JMenuItem viewDrivers = new JMenuItem("View / Edit Drivers");
        viewDrivers.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                new ViewDriversFrame(getXBound(), getYBound());
            }
        });
        drivers.add(viewDrivers);

        drivers.add(new JSeparator());
        JMenuItem addTimeSlot = new JMenuItem("Add Time Slot");
        addTimeSlot.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                new AddTimeSlotFrame(getXBound(), getYBound());
            }
        });
        drivers.add(addTimeSlot);

        JMenuItem viewTimeSlots = new JMenuItem("View / Edit Time Slots");
        viewTimeSlots.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                new ViewTimeSlotsFrame(getXBound(), getYBound());
            }
        });
        drivers.add(viewTimeSlots);

        JMenu vehicles = new JMenu("Vehicles");

        JMenuItem addVehicle = new JMenuItem("Add Vehicle");
        addVehicle.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                new AddVehicleFrame(getXBound(), getYBound());
            }
        });
        vehicles.add(addVehicle);
        JMenuItem viewVehicles = new JMenuItem("View / Edit Vehicles");
        viewVehicles.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                new ViewVehiclesFrame(getXBound(), getYBound());
            }
        });
        vehicles.add(viewVehicles);
        vehicles.add(new JSeparator());

        JMenuItem addVehicleType = new JMenuItem("Add Vehicle Type");
        addVehicleType.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                new AddVehicleTypeFrame(getXBound() + 50, getYBound() + 50);
            }
        });
        vehicles.add(addVehicleType);

        JMenuItem viewVehicleTypes = new JMenuItem("View / Edit Vehicle Types");
        viewVehicleTypes.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                new ViewVehicleTypesFrame(getXBound(), getYBound());
            }
        });
        vehicles.add(viewVehicleTypes);

        JMenu users = new JMenu("Users");
        JMenuItem addUser = new JMenuItem("Add User");
        addUser.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                new AddUserFrame(getX(), getY());
            }
        });
        users.add(addUser);
        JMenuItem viewUser = new JMenuItem("View / Edit Users");
        viewUser.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                new ViewUsersFrame(getX(), getY());
            }
        });
        users.add(viewUser);

        menuBar.add(file);
        menuBar.add(drivers);
        menuBar.add(vehicles);
        menuBar.add(users);
        this.setJMenuBar(menuBar);

        this.setVisible(true);

    }

    public static void main(String[] args) {
        new mainFrame();
    }

    public int getXBound() {
        return this.getX();
    }

    public int getYBound() {
        return this.getY();
    }

    public static void updateTable() {

        List<Event> eventsTemp = new ArrayList<Event>();
        mutableCal.setTimeInMillis(cal.getTimeInMillis());
        eventsList = EventDAO.getEventsByDate(new Date(cal.getTimeInMillis()));
        EventHandler.sortEvents((ArrayList<Event>) eventsList, EventHandler.SORT_BY_DEPART_TIME);

        switch (radioSet) {
            case 0:
                for (int i = 0; i < 6; i++) {
                    mutableCal.setTimeInMillis(mutableCal.getTimeInMillis() + (1000 * 60 * 60 * 24));
                    eventsTemp = EventDAO.getEventsByDate(new Date(mutableCal.getTimeInMillis()));
                    EventHandler.sortEvents((ArrayList<Event>) eventsTemp, EventHandler.SORT_BY_DEPART_TIME);
                    eventsList.addAll(eventsTemp);
                }
                break;
            case 1:
                break;
        }

        events = new Object[eventsList.size()][9];
        long depart, driveTime;
        for (int i = 0; i < eventsList.size(); i++) {
            events[i][0] = sdf.format(eventsList.get(i).getDate());
            events[i][1] = eventsList.get(i).getService().getDriveTime() + " mins";
            depart = eventsList.get(i).getService().getStartTime().getTime();
            driveTime = eventsList.get(i).getService().getDriveTime() * 60 * 1000;
            events[i][2] = sdf2.format(new Date(depart - driveTime));
            events[i][3] = eventsList.get(i).getDriver();
            events[i][4] = eventsList.get(i).getVehicle();
            events[i][5] = sdf2.format(eventsList.get(i).getService().getStartTime());
            events[i][6] = eventsList.get(i).getService().getName();
            events[i][7] = eventsList.get(i).getService().getTransnumb();
            depart = eventsList.get(i).getService().getEndTime().getTime();
            events[i][8] = eventsList.get(i).getNotes();
        }
        model = new MyTableModel(events, columnNames);
        table = new myTable(model);
        table.setRowHeight(30);
        table.getTableHeader().setReorderingAllowed(false);
        //table.addRowSelectionInterval(0, 0);
        TableColumn col = table.getColumnModel().getColumn(3);
        col.setCellRenderer(new cellRenderer());
        TableColumn col2 = table.getColumnModel().getColumn(4);
        col2.setCellRenderer(new cellRenderer());
        TableColumn col3 = table.getColumnModel().getColumn(8);
        col3.setCellEditor(new customNotesEditor(new JTextField()));
        content.remove(scrollpane);
        scrollpane = new JScrollPane(table);
        scrollpane.setBounds(50, 50, 900, 400);
        content.add(scrollpane);
    }

    public static boolean getAllDriversBool() {
        return allDriversBool;
    }
}

class customNotesEditor extends DefaultCellEditor{
    public customNotesEditor(final JTextField f){
        super(f);

        this.addCellEditorListener(new CellEditorListener() {

            @Override
            public void editingStopped(ChangeEvent e) {
                mainFrame.editingEvent.setNotes(f.getText());
                EventDAO.saveEvent(mainFrame.editingEvent);
            }

            @Override
            public void editingCanceled(ChangeEvent e) {

            }
        });

    }

}


class customDriverEditor extends DefaultCellEditor {

    public customDriverEditor(final JComboBox arg0) {

        super(arg0);

        this.addCellEditorListener(new CellEditorListener() {

            @Override
            public void editingStopped(ChangeEvent e) {
                if (mainFrame.table.getSelectedColumn() == 3) {
                    mainFrame.selectedIndex = arg0.getSelectedIndex();
                    mainFrame.eventsList.get(mainFrame.table.getSelectedRow()).setDriverID(((Driver) arg0.getSelectedItem()).getId());
                    Object[] options = {"Default Driver", "Substitute Driver", "Cancel"};
                    int choice = JOptionPane.showOptionDialog(getComponent(), "Set as Default Driver or Subsititute?", "Set as Default Driver?", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
                    switch (choice) {
                        case 0:
                            mainFrame.eventsList.get(mainFrame.table.getSelectedRow()).setDefaultDriverID(((Driver) arg0.getSelectedItem()).getId());
                            EventDAO.saveEvent(mainFrame.eventsList.get(mainFrame.table.getSelectedRow()));
                            break;
                        case 1:
                            EventDAO.saveEvent(mainFrame.eventsList.get(mainFrame.table.getSelectedRow()));
                            break;
                        case 2:
                            for (int i = 0; i < arg0.getItemCount(); i++) {
                                if (mainFrame.eventsList.get(mainFrame.table.getSelectedRow()).getDriver().toString().equals(arg0.getItemAt(i).toString())) {
                                    arg0.setSelectedIndex(i);
                                    mainFrame.table.setValueAt(mainFrame.eventsList.get(mainFrame.table.getSelectedRow()).getDriver(), mainFrame.table.getSelectedRow(), 3);
                                }
                            }
                            break;

                        default:
                            break;
                    }
                } else {
                    mainFrame.selectedIndex = arg0.getSelectedIndex();
                }
            }

            @Override
            public void editingCanceled(ChangeEvent e) {
                // TODO Auto-generated method stub
            }
        });
    }
}

class customVehicleEditor extends DefaultCellEditor {

    public customVehicleEditor(final JComboBox arg0) {

        super(arg0);

        this.addCellEditorListener(new CellEditorListener() {

            @Override
            public void editingStopped(ChangeEvent e) {
                if (mainFrame.table.getSelectedColumn() == 4) {
                    mainFrame.selectedIndex = arg0.getSelectedIndex();
                    mainFrame.eventsList.get(mainFrame.table.getSelectedRow()).setVehicleID(((Vehicle) arg0.getSelectedItem()).getId());
                    EventDAO.saveEvent(mainFrame.eventsList.get(mainFrame.table.getSelectedRow()));
                } else {
                    mainFrame.selectedIndex = arg0.getSelectedIndex();
                }
            }

            @Override
            public void editingCanceled(ChangeEvent e) {
                // TODO Auto-generated method stub
            }
        });
    }
}

class cellRenderer extends JLabel implements TableCellRenderer {

    public cellRenderer() {
        super();
        this.setOpaque(true);

    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        setFont(table.getFont());

        if (isSelected) {
            setForeground(table.getSelectionForeground());
            super.setBackground(table.getSelectionBackground());
        } else {
            setForeground(table.getForeground());
            setBackground(table.getBackground());
        }

        if (value != null) {

            setText(value.toString());

        }

        if (value != null && value.toString().contains("Fleet")) {
            setForeground(new Color(0, 150, 0));
        } else if (value == null) {
            setText("");
            setBackground(Color.YELLOW);
        }
        return this;
    }
}

class myTable extends JTable {

    public myTable(TableModel m) {
        super(m);
    }

    @Override
    public TableCellEditor getCellEditor(int row, int col) {

        Event e = mainFrame.eventsList.get(row);

        if (col == 3) {

            List<Driver> possDrivers;
            if (mainFrame.getAllDriversBool()) {
                possDrivers = DriverDAO.getDrivers();
            } else {
                possDrivers = e.getPossibleDrivers();
            }

            Driver[] possDriversArray = new Driver[possDrivers.size()];

            for (int i = 0; i < possDrivers.size(); i++) {
                possDriversArray[i] = possDrivers.get(i);
            }

            int index = 0;
            JComboBox box = new JComboBox(possDriversArray);
            box.addItem(null);
            if (e.getDriver() != null) {
                for (int i = 0; i < possDriversArray.length; i++) {
                    if (e.getDriver().toString().equals(possDriversArray[i].toString())) {
                        index = i;
                    }
                }

                box.setSelectedIndex(index);
            }
            return new customDriverEditor(box);
        } else if (col == 4) {
            List<Vehicle> possVehicles = VehicleDAO.getVehicles();
            Vehicle[] possVehiclesArray = new Vehicle[possVehicles.size()];

            for (int i = 0; i < possVehicles.size(); i++) {
                possVehiclesArray[i] = possVehicles.get(i);
            }

            int index = 0;
            JComboBox box = new JComboBox(possVehiclesArray);
            for (int i = 0; i < possVehiclesArray.length; i++) {
                if (e.getVehicle() != null) {
                    if (e.getVehicle().toString().equals(possVehiclesArray[i].toString())) {
                        index = i;
                    }
                }
                box.setSelectedIndex(index);
            }

            return new customVehicleEditor(box);
        } else if (col==8){
            mainFrame.editingEvent = mainFrame.eventsList.get(row);
            return new customNotesEditor(new JTextField());
            
        } else {
            return super.getCellEditor();
        }

    }
}
